/*
 * FixedSizeBlockFile.cpp
 *
 *  Created on: Oct 10, 2012
 *      Author: m
 */

#include "FixedSizeBlockFile.h"

namespace physical
{

const openmode FixedSizeBlockFile::defaulOpenmode = std::ios_base::in
        | std::ios_base::out | std::ios_base::app | std::ios_base::binary;

FixedSizeBlockFile::FixedSizeBlockFile( size_t blockSize, const char filename[],
        openmode mode ) :
        m_blockSource(), m_blockSize( blockSize )
{
    m_blockSource.exceptions( std::fstream::failbit | std::fstream::badbit );

    if ( filename != NULL && filename[0] != '\0' )
        this->open( filename, mode );
}

FixedSizeBlockFile::~FixedSizeBlockFile()
{
    this->close();
}

void FixedSizeBlockFile::readBlock( blockNumber position, byteStream buffer )
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    blockNumber nextPosition = position * m_blockSize;
    m_blockSource.seekg( nextPosition );

    this->readBlock( buffer );
}

// Escritura NO Secuencial
void FixedSizeBlockFile::writeBlock( blockNumber position,
        const byteStream buffer )
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    blockNumber nextPosition = position * m_blockSize;
    m_blockSource.seekp( nextPosition );

    this->writeBlock( buffer );
}

size_t FixedSizeBlockFile::getBlockSize() const
{
    return m_blockSize;
}

size_t FixedSizeBlockFile::getFileSize() const
{
    std::streampos fsize = 0;
    std::fstream* fsp = (std::fstream*) &m_blockSource;

    // save initial stream state and position
    auto initialState = fsp->rdstate();
    auto initialPosition = fsp->tellg();

    // compute file size
    fsp->clear();
    fsp->seekg( 0, std::ios::beg );
    fsize = fsp->tellg();
    fsp->clear();
    fsp->seekg( 0, std::ios::end );
    fsize = fsp->tellg() - fsize;

    // Restore initial stream state and position
    fsp->setstate( initialState );
    fsp->seekg( initialPosition );

    return fsize;
}

size_t FixedSizeBlockFile::gcount() const
{
    return m_blockSource.gcount();
}

size_t FixedSizeBlockFile::getBlocksCount() const
{
    if ( m_blockSize <= 0 )
        throw InvalidBlockSizeException();

    return this->getFileSize() / m_blockSize;
}

bool FixedSizeBlockFile::eof() const
{
    return m_blockSource.eof();
}

void FixedSizeBlockFile::open( const char filename[], openmode mode )
{
    if ( m_blockSource.is_open() )
        return;

    m_blockSource.open( filename, mode | std::ios_base::binary );
}

void FixedSizeBlockFile::close()
{
    if ( m_blockSource.is_open() )
        m_blockSource.close();
}

void FixedSizeBlockFile::resetBlockSize( size_t blockSize )
{
    m_blockSize = blockSize;
}

void FixedSizeBlockFile::readBlock( byteStream buffer )
{
    m_blockSource.read( buffer, m_blockSize );
}

void FixedSizeBlockFile::writeBlock( const byteStream buffer )
{
    m_blockSource.write( buffer, m_blockSize );
}

} /* namespace physical */
